package dao.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import model.impl.network.TrackImpl;

import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.resotc.dao.TrackDAO;
import org.resotc.model.ElementType;
import org.resotc.model.Phasen;
import org.resotc.model.Track;

public class TrackDAOImpl extends AbstractXMLDAO implements TrackDAO {

	private final static String indexFileName = "tracks.xml";
	private HashMap<Integer, Track> tracks;
	
	public TrackDAOImpl() throws JDOMException, IOException {
		indexFile = new File(rootPath + "/" + indexFileName);
		loadXML();
		parseXML();
	}

	/**
	 * @see TrackDAO#getTrack(int)
	 */
	public Track getTrack(int id) {
		return tracks.get(id);
	}

	/**
	 * @see TrackDAO#getTracks()
	 */
	public HashMap<Integer, Track> getTracks() {
		return tracks;
	}

	/**
	 * @see TrackDAO#createTrack(Track)
	 */
	public void createTrack(Track track) {
		createAndUpdateTrack(track);
	}

	/**
	 * @see TrackDAO#updateTrack(Track)
	 */
	public void updateTrack(Track track) {
		createAndUpdateTrack(track);
	}

	/**
	 * @see TrackDAO#deleteTrack(int)
	 */
	public void deleteTrack(int id) {
		Element rootElement = indexXMLInstance.getRootElement();
		Iterator<Element> it = rootElement.getChild("tracks").getChildren().iterator();

		while (it.hasNext()) {
			Element track = it.next();
			int trackId = Integer.parseInt(track.getChildText("id"));

			if (trackId == id) {
				it.remove();
				break;
			}
		}
		tracks.remove(tracks.get(id));
		storeXML();
	}

	/**
	 * @see TrackDAO#trackExists(int)
	 */
	public boolean trackExists(int id) {
		return tracks.containsKey(id);
	}

	private void createAndUpdateTrack(Track track) {
		Element newElement = new Element("track");

		newElement.addContent(new Element("id").setText(String.valueOf(track.getId())));
		newElement.addContent(new Element("type").setText(String.valueOf(track.getElementType())));
		newElement.addContent(new Element("dst_tracks"));

		List<Track> dstTrackList = new ArrayList<Track>(track.getDstTracks());

		for (Track dstTrack : dstTrackList) {
			Element dstTrackElement = new Element("track");
			dstTrackElement.addContent(String.valueOf(dstTrack.getId()));
			newElement.addContent(dstTrackElement);
		}
		// if track already exists
		if (tracks.containsKey(track.getId())) {
			Element rootElement = indexXMLInstance.getRootElement();
			Element trackElements = rootElement.getChild("tracks");

			List<Element> trackList = new ArrayList<Element>(trackElements.getChildren());

			for (Element exstTrack : trackList) {
				int id = Integer.parseInt(exstTrack.getChildText("id"));

				if (id == track.getId()) {
					trackElements.removeContent(exstTrack);
					rootElement.getChild("tracks").addContent(newElement);
					tracks.put(track.getId(), track);
				}
			}
		}
		storeXML();
	}

	/**
	 * Parses the tracks.xml.
	 */
	private void parseXML() {
		tracks = new HashMap<Integer, Track>();

		Element rootElement = indexXMLInstance.getRootElement();
		Element trackElements = rootElement.getChild("tracks");

		HashMap<Integer, Track> dstTracks = new HashMap<Integer, Track>();

		List<Element> list = trackElements.getChildren();

		// at first dst tracks are parsed, so they can be used by the src tracks
		for (Element element : list) {
			ElementType type = ElementType.valueOf(element.getChildText("type").toUpperCase());
			if (type == ElementType.OUTGOING) {
				int id = Integer.parseInt(element.getChildText("id"));
				Phasen phase = Phasen.valueOf(element.getChildText("phase").toUpperCase());
				int queueId = Integer.parseInt(element.getChildText("queue"));
				
				Track dstTrack = new TrackImpl(id, type, null, phase, queueId);
				dstTracks.put(id, dstTrack);
			}
		}

		for (Element element : list) {
			int id = Integer.parseInt(element.getChildText("id"));
			ElementType type = ElementType.valueOf(element.getChildText("type").toUpperCase());
			Phasen phase = Phasen.valueOf(element.getChildText("phase").toUpperCase());
			int queueId = Integer.parseInt(element.getChildText("queue"));
			ArrayList<Track> dstTrackList = new ArrayList<Track>();

			if (!(type == ElementType.OUTGOING)) {
				List<Element> dstList = element.getChild("dst_tracks").getChildren();
				
				for (Element dst : dstList) {
				
					int dstTrackId = Integer.parseInt(dst.getText());
					Track dstTrack = dstTracks.get(dstTrackId);
					dstTrackList.add(dstTrack);
				}
			}

			Track track = new TrackImpl(id, type, dstTrackList, phase, queueId);
			tracks.put(id, track);
			dstTrackList.clear();
		}
	}
}
